import sqlite3
from typing import Dict, List, Tuple
from LogManager import log_output


# Book Database
DATABASE = 'database/book_data.db'


class BookInfo:
    def __init__(self, book_id, title, author, shortintro, cate, cover, publisher, year):
        self.book_id = book_id
        self.title = title
        self.author = author
        self.shortintro = shortintro
        self.cate = cate
        self.cover = cover
        self.publisher = publisher
        self.year = year


class BookManager:
    """
        book_info(book_id,title,author,shortintro,cate,cover,publisher,year)
        book_text(book_id,chapter_num,chapter_title,chapter_text)
    """

    def __init__(self):
        self.database = DATABASE

    def get_conn(self):
        self.conn = sqlite3.connect(self.database)
        return self.conn

    def close_conn(self):
        if self.conn is None:
            return

        try:
            self.conn.close()
        except Exception as err:
            log_output(str(err))

        self.conn = None

    def get_book_info(self, book_id: int) -> BookInfo:
        try:
            sql = f'SELECT * FROM book_info WHERE book_id = {book_id}'
            conn = self.get_conn()
            cursor = conn.cursor()
            rows = cursor.execute(sql)

            result = None
            for row in rows:
                result = BookInfo(row[0], row[1], row[2],
                                  row[3], row[4], row[5], row[6], row[7])

            if result is None:
                raise ValueError()

            return result
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def book_id_exists(self, book_id: int) -> bool:
        try:
            sql = f'SELECT COUNT(*) FROM book_info WHERE book_id = {book_id}'
            conn = self.get_conn()
            cursor = conn.cursor()
            rows = cursor.execute(sql)

            result = None
            for row in rows:
                result = row[0]

            return (result >= 1)
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def request_book_info(self, send_data: Dict[str, str]) -> Dict[str, str]:
        assert type(send_data) == dict and 'book_id' in send_data
        book_id = int(send_data['book_id'])
        try:
            book_info = self.get_book_info(book_id)

            return_dict = {
                'type': 0,
                'book_id': book_id,
                'title': book_info.title,
                'author': book_info.author,
                'shortIntro': book_info.shortintro,
                'cate': book_info.cate,
                'cover': book_info.cover,
                'label': '推荐'
            }

            return return_dict
        except Exception as err:
            log_output(str(err))
            err_info = {
                'type': 1
            }

            return err_info

    def request_book_info_with_name(self, name: str) -> Dict[str, str]:
        try:
            sql = f'SELECT * FROM book_info WHERE title = \'{name}\''
            conn = self.get_conn()
            cursor = conn.cursor()
            rows = cursor.execute(sql)

            result = None
            for row in rows:
                result = {
                    'book_id': row[0],
                    'title': row[1],
                    'author': row[2],
                    'shortIntro': row[3],
                    'cate': row[4],
                    'cover': row[5],
                    'label': '推荐'
                }
                break

            if result is not None:
                return result

            raise ValueError(f"No such book: {name}")
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def request_chapter_text(self, send_data):
        assert type(send_data) == dict
        assert 'book_id' in send_data and 'chapter_num' in send_data

        book_id = int(send_data['book_id'])
        chapter_num = int(send_data['chapter_num'])

        try:
            sql = f'SELECT * FROM book_text WHERE book_id = {book_id} AND chapter_num = {chapter_num}'
            conn = self.get_conn()
            cursor = conn.cursor()
            rows = cursor.execute(sql)

            chapter_title = None
            chapter_text_pos = None
            for row in rows:
                chapter_title = row[2]
                chapter_text_pos = row[3]

            if chapter_text_pos is None:
                raise ValueError()

            # Count
            sql = f'SELECT COUNT(*) FROM book_text WHERE book_id = {book_id}'
            rows = cursor.execute(sql)
            count = 0

            for row in rows:
                count = row[0]

            # Read Content
            with open(chapter_text_pos, 'rt') as f:
                chapter_text = f.read()

            return_dict = {
                'type': 0,
                'book_id': book_id,
                'chapter_title': chapter_title,
                'total': count,
                'body': chapter_text
            }

            return return_dict
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def request_search(self, send_data):
        assert type(send_data) == dict
        assert 'search' in send_data

        search_content = send_data['search']

        try:
            sql = f'SELECT * FROM book_info WHERE title LIKE \'%{search_content}%\''
            conn = self.get_conn()
            cursor = conn.cursor()
            rows = cursor.execute(sql)

            books = []
            for row in rows:
                books.append({
                    "book_id": row[0],
                    "title": row[1],
                    "author": row[2],
                    "shortIntro": row[3],
                    "cate": row[4],
                    "cover": row[5],
                    "label": "推荐"
                })

            return_dict = {
                "ok": True,
                "total": len(books),
                "books": books
            }

            return return_dict
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def request_special_search(self, send_data):
        assert type(send_data) == dict
        assert 'book_id' in send_data

        search_content = send_data['book_id']
        try:
            book_id = int(search_content)
        except Exception as err:
            log_output(err)
            raise ValueError(f"Book id {search_content} not int value!")

        try:
            sql = f'SELECT * FROM book_info WHERE book_id = {book_id}'
            conn = self.get_conn()
            cursor = conn.cursor()
            rows = cursor.execute(sql)

            books = []
            for row in rows:
                books.append({
                    "book_id": row[0],
                    "title": row[1],
                    "author": row[2],
                    "shortIntro": row[3],
                    "cate": row[4],
                    "cover": row[5],
                    "label": "推荐"
                })

            return_dict = {
                "ok": True,
                "total": len(books),
                "books": books
            }

            return return_dict
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()
